package com.singfan.core.service.impl;

import com.pingplusplus.model.Charge;
import com.singfan.common.util.JsonUtil;
import com.singfan.core.dao.database.*;
import com.singfan.core.dao.database.model.*;
import com.singfan.core.dao.database.model.constant.OrderStatusType;
import com.singfan.core.dao.database.model.temp.OrderContent;
import com.singfan.core.dao.database.model.temp.OrderItem;
import com.singfan.core.service.IOrderService;
import com.singfan.core.util.PayUtil;
import com.singfan.core.util.PushUtil;
import com.singfan.core.util.ReservationCodeUtil;
import com.singfan.core.util.SmsUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * Author: hansonghe
 * Date: 2015-08-27 15:06
 * Desc:
 */
@Service
public class OrderServiceImpl implements IOrderService {
    @Autowired
    private IOrderDao orderDao;
    @Autowired
    private IOrderPayChannelInfoDao orderPayChannelInfoDao;
    @Autowired
    private IBarberDao barberDao;
    @Autowired
    private IShopHairDao shopHairDao;
    @Autowired
    private IBarberCommentDao barberCommentDao;
    @Autowired
    private IBarberAppointmentDao barberAppointmentDao;
    @Autowired
    private IShopHairAppointmentSummaryDao shopHairAppointmentSummaryDao;
    @Autowired
    private IShopHairAppointmentDetailDao shopHairAppointmentDetailDao;
    @Autowired
    private ICustomerCouponDao customerCouponDao;
    @Autowired
    private ICustomerDao customerDao;
    @Autowired
    private IJpushInfoDao jpushInfoDao;

    @Override
    public String createOrder(Customer customer, Shop shop, Barber barber, int orderType, BarberHairstyle barberHairstyle, List<ShopHairService> shopHairServiceList, int payChannelType, long couponId, int realOriginalPriceCount, int price, int appointmentDay, int appointmentClock, String clientIp) {
        String result = null;

        boolean isExist = orderDao.isExist(barber.getId(), appointmentDay, appointmentClock);
        if (!isExist){
            Orders order = new Orders();
            order.setReservationCode(ReservationCodeUtil.createReservationCode("r-" + customer.getId() + shop.getId() + barber.getId(), 6));
            OrderContent orderContent = new OrderContent();
            orderContent.setOrderItemList(new ArrayList<>());
            if (orderType == 1){
                order.setOrderIcon(barberHairstyle.getPreferredImg());
                order.setOrderName(barberHairstyle.getHairstyleName());


                OrderItem orderItem = new OrderItem();
                orderItem.setServiceType(orderType);
                orderItem.setServiceId(barberHairstyle.getId());
                orderItem.setServiceName(barberHairstyle.getHairstyleName());
                orderItem.setPrice(price);

                orderContent.getOrderItemList().add(orderItem);
            }
            else {
                order.setOrderIcon(shop.getShopIconUrl());
                String orderName = "";
                int hairServiceCount = shopHairServiceList.size();
                for (int i=0; i<hairServiceCount; i++){
                    ShopHairService shopHairService = shopHairServiceList.get(i);
                    if (i == 0){
                        orderName += shopHairService.getServiceName();
                    }
                    else {
                        orderName += "," + shopHairService.getServiceName();
                    }

                    OrderItem orderItem = new OrderItem();
                    orderItem.setServiceType(orderType);
                    orderItem.setServiceId(shopHairService.getId());
                    orderItem.setServiceName(shopHairService.getServiceName());
                    orderItem.setPrice(price);

                    orderContent.getOrderItemList().add(orderItem);
                }
                order.setOrderName(orderName);
            }

            order.setCustomerId(customer.getId());
            order.setCustomerName(customer.getNickName());
            order.setCustomerGender(customer.getGender());
            order.setCustomerPhoneNumber(customer.getPhoneNumber());
            order.setCustomerPhoneType(customer.getPhoneType());
            order.setBarberId(barber.getId());
            order.setBarberName(barber.getNickName());
            order.setBarberPhoneNumber(barber.getPhoneNumber());
            order.setShopId(shop.getId());
            order.setShopName(shop.getMasterShopName() + " " + shop.getSlaveShopName());
            order.setShopAddress(shop.getAddress());
            order.setLongitude(shop.getLongitude());
            order.setLatitude(shop.getLatitude());
            order.setShopPhone(shop.getContactNumber());
            order.setCityId(shop.getCityId());
            order.setOrderType(orderType);
            order.setPayChannelType(payChannelType);
            order.setOriginalPrice(realOriginalPriceCount);
            order.setPrice(price);
            order.setServiceContext(JsonUtil.bean2Json(orderContent));
            order.setAppointmentDay(appointmentDay);
            order.setAppointmentClock(appointmentClock);
            order.setStatus(OrderStatusType.UNPAID);
            order.setComplaints(false);
            order.setCommentStar(0);
            order.setCreateTime(new Date());
            order.setUpdateTime(order.getCreateTime());

            orderDao.create(order);

            Charge charge = PayUtil.charge(price, "order-" + order.getId(), "" + customer.getId() + "-" + shop.getId() + "-" + price, String.valueOf(order.getId()), payChannelType, clientIp);
            if (charge != null) {
                BarberAppointment barberAppointment = barberAppointmentDao.selectAppointmentByDayClockTime(barber.getId(), appointmentDay, appointmentClock);
                if (barberAppointment == null){
                    orderDao.updateChannelSerialNumber(order.getId(), charge.getId());

                    OrderPayChannelInfo orderPayChannelInfo = new OrderPayChannelInfo();
                    orderPayChannelInfo.setOrderId(order.getId());
                    orderPayChannelInfo.setChargeContent(charge.toString());

                    orderPayChannelInfoDao.create(orderPayChannelInfo);

                    barberAppointment = new BarberAppointment();
                    barberAppointment.setBarberId(barber.getId());
                    barberAppointment.setCustomerId(order.getCustomerId());
                    barberAppointment.setOrderId(order.getId());
                    barberAppointment.setAppointmentDay(order.getAppointmentDay());
                    barberAppointment.setAppointmentClock(order.getAppointmentClock());
                    barberAppointment.setCreateTime(new Date());
                    barberAppointmentDao.create(barberAppointment);

                    shopHairAppointmentSummaryDao.increaseAppointmentCount(shop.getId(), appointmentDay, appointmentClock);

                    ShopHairAppointmentDetail shopHairAppointmentDetail = new ShopHairAppointmentDetail();
                    shopHairAppointmentDetail.setShopId(shop.getId());
                    shopHairAppointmentDetail.setBarberId(barber.getId());
                    shopHairAppointmentDetail.setCustomerId(customer.getId());
                    shopHairAppointmentDetail.setOrderId(order.getId());
                    shopHairAppointmentDetail.setAppointmentDay(appointmentDay);
                    shopHairAppointmentDetail.setAppointmentClock(appointmentClock);
                    shopHairAppointmentDetail.setCreateTime(new Date());
                    shopHairAppointmentDetailDao.create(shopHairAppointmentDetail);

                    customerCouponDao.setOrderId(couponId, order.getId());

                    result = charge.toString();
                }
                else {
                    orderDao.deleteById(order.getId());
                    result = APPOINTMENT_CONFLICT;
                }
            }
            else {
                orderDao.deleteById(order.getId());
            }
        }
        else{
            result = APPOINTMENT_CONFLICT;
        }

        return result;
    }

    @Override
    public void updateOrderPaied(String payChannelSerialNumber) {
        Orders orders = orderDao.selectOrder(payChannelSerialNumber);
        if (orders != null){
            orders.setStatus(OrderStatusType.PAID);
            orders.setUpdateTime(new Date());

            orderDao.update(orders);

            customerCouponDao.deleteByOrderId(orders.getId());

            JpushInfo jpushInfo = jpushInfoDao.selectByUserId(orders.getBarberId());
            if (jpushInfo != null){
                String content = String.format("%1$s 已预约 %2$s %3$s 的剪发服务", orders.getCustomerPhoneNumber(), formatDayTime(orders.getAppointmentDay()), formatClockTime(orders.getAppointmentClock()));
                PushUtil.push(jpushInfo.getRegistrationCode(), jpushInfo.getUserType(), jpushInfo.getPlatformType(), content);
            }

            //TODO:暂时不给用户发送验证码短信通知，等门店端做完再放开
            SmsUtil.sendReservationCode(orders.getCustomerPhoneNumber(), orders.getReservationCode());
        }
    }

    @Override
    public List<Orders> findCustomerOrderList(long customerId, int orderStatusType, int pageIndex, int pageSize) {
        return orderDao.selectCustomerOrderList(customerId, orderStatusType, pageIndex, pageSize);
    }

    @Override
    public OrderPayChannelInfo findOrderPayChannelInfo(long orderId) {
        return orderPayChannelInfoDao.selectById(orderId);
    }

    @Override
    public void commentOrder(long orderId, long customerId, int serviceLevel, int techLevel, int environmentLevel, String commentContent, List<String> commentImgUrl) {
        Orders order = orderDao.selectOrder(orderId);
        if (order != null && order.getCustomerId() == customerId && order.getCommentStar() == 0){
            int barberCommentStar = (serviceLevel + techLevel) / 2;
            orderDao.updateCommentStar(orderId, barberCommentStar);

            long barberId = order.getBarberId();
            Barber barber = barberDao.selectBarberById(barberId);
            barber.setCommentCount(barber.getCommentCount() + 1);
            if (barberCommentStar >= 6){
                barber.setFavorableCommentCount(barber.getFavorableCommentCount() + 1);
            }
            barber.setCommentScore(barber.getCommentScore() + barberCommentStar);
            barber.setHonor((int)Math.round(barber.getCommentScore() * 1.00 / barber.getCommentCount()));
            barberDao.updateComment(barberId, barber.getCommentCount(), barber.getFavorableCommentCount(), barber.getCommentScore(), barber.getHonor());

            ShopHair shopHair = shopHairDao.selectShopHair(order.getShopId());
            shopHair.setCommentCount(shopHair.getCommentCount() + 1);
            shopHair.setCommentScore(shopHair.getCommentScore() + environmentLevel);
            shopHair.setHonor((int)Math.round(shopHair.getCommentScore()*1.0 / shopHair.getCommentCount()));
            shopHairDao.updateComment(shopHair.getShopId(), shopHair.getCommentCount(), shopHair.getCommentScore(), shopHair.getHonor());

            Customer customer = customerDao.findCustomer(customerId);

            BarberComment barberComment = new BarberComment();
            barberComment.setCustomerAvatar(customer.getAvatar());
            barberComment.setBarberId(barberId);
            barberComment.setCustomerId(customerId);
            barberComment.setCustomerName(order.getCustomerName());
            barberComment.setCommentStar(barberCommentStar);
            barberComment.setCommentText(commentContent);
            String imgUrls = "";
            if (commentImgUrl.size() > 0){
                for(String url : commentImgUrl){
                    imgUrls += url + ";";
                }
                imgUrls = imgUrls.substring(0, imgUrls.length() -1);
            }
            barberComment.setCommentImgList(imgUrls);
            barberComment.setCreateTime(new Date());
            barberCommentDao.create(barberComment);
        }
    }

    @Override
    public int barberOrderCount(long barberId) {
        return orderDao.barberOrderCount(barberId);
    }

    @Override
    public int barberUnfinishOrderCount(long barberId) {
        return orderDao.barberUnfinishOrderCount(barberId);
    }

    @Override
    public List<Orders> findBarberOrderList(long barberId, int orderStatusType, int pageIndex, int pageSize) {
        return orderDao.selectBarberOrderList(barberId, orderStatusType, pageIndex, pageSize);
    }

    @Override
    public List<Long> findExpiredOrder(Date limitCreateTime) {
        return orderDao.selectExpiredOrder(limitCreateTime);
    }

    @Override
    public void updateOrderStatus(long orderId, int status) {
        orderDao.updateStatus(orderId, status);
    }

    @Override
    public LinkedHashMap<Integer, Integer> findBarberIncomeTotalByMonth(long barberId) {
        return orderDao.selectBarberIncomeTotalByMonth(barberId);
    }

    @Override
    public int findBarberIncomeTotal(long barberId){
        return orderDao.selectBarberIncomeTotal(barberId);
    }

    @Override
    public List<Orders> findBarberOrderDetailList(long barberId, int orderFilterType, int pageIndex, int pageSize) {
        return orderDao.selectBarberOrderDetailList(barberId, orderFilterType, pageIndex, pageSize);
    }

    @Override
    public Orders findOrdersById(long orderId) {
        return orderDao.selectOrder(orderId);
    }

    @Override
    public void updateOrderServiced(long orderId) {
        orderDao.updateOrderServiced(orderId);
    }

    @Override
    public int findShopOneDayIncome(long shopId, int dayTime) {
        return orderDao.selectShopOneDayIncome(shopId, dayTime);
    }

    @Override
    public int findShopOneDayOrderCount(long shopId, int dayTime) {
        return orderDao.selectShopOneDayOrderCount(shopId, dayTime);
    }

    @Override
    public List<Orders> findShopOneDayOrderList(long shopId, int dayTime) {
        return orderDao.selectShopOneDayOrderList(shopId, dayTime);
    }

    @Override
    public int findShopOneMonthIncome(long shopId, int monthTime) {
        return orderDao.selectShopOneMonthIncome(shopId, monthTime);
    }

    @Override
    public int findShopOneMonthOrderCount(long shopId, int monthTime) {
        return orderDao.selectShopOneMonthOrderCount(shopId, monthTime);
    }

    @Override
    public Orders findOrdersBySecurityCode(long shopId, String securityCode) {
        return orderDao.selectOrdersBySecurityCode(shopId, securityCode);
    }

    @Override
    public List<Orders> findShopOrderDetailList(long shopId, int orderFilterType, int pageIndex, int pageSize) {
        return orderDao.selectShopOrderDetailList(shopId, orderFilterType, pageIndex, pageSize);
    }

    @Override
    public List<Orders> findCustomerOrderList(String customerPhone) {
        return orderDao.selectCustomerOrderList(customerPhone);
    }

    @Override
    public List<Orders> findOneMonthOrdersList(int month, long shopId) {
        return orderDao.selectOneMonthOrdersList(month, shopId);
    }

    private static String formatDayTime(int dayTime){
        String dayTimeStr = String.valueOf(dayTime);
        return dayTimeStr.substring(0,4) + "/" + dayTimeStr.substring(4,6) + "/" + dayTimeStr.substring(6);
    }

    private static String formatClockTime(int clockTime){
        String clockTimeStr = String.valueOf(clockTime);
        return clockTimeStr.substring(0,2) + ":" + clockTimeStr.substring(2);
    }
}
